﻿using Apache.NMS;
using Apache.NMS.ActiveMQ;
using Apache.NMS.ActiveMQ.Commands;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Data;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using WRJClient.Common;
using WRJClient.Utils;
using static System.Net.Mime.MediaTypeNames;

namespace WRJClient.Net
{
    public sealed class ActiveMqConnector
    {
        private Logger _logger = null;
        private static readonly ActiveMqConnector _instance = new ActiveMqConnector();

        private IConnection _connection = null;
        private ISession _session = null;
        private bool _isConnecting = false;
        private string _clientId = "";

        public static ActiveMqConnector GetInstance() { return _instance; }
        private ActiveMqConnector()
        {
            _logger = new Logger("topic");
        }
        public string ClientId { get { return _clientId; } set { _clientId = value; } }

        private void Connection_ExceptionListener(Exception exception)
        {
            MessageBox.Show(exception.ToString());
            reconnect();
        }

        private void Connection_ConnectionResumedListener()
        {
            MessageBox.Show("Connection_ConnectionResumedListener");
        }

        private void Connection_ConnectionInterruptedListener()
        {
            MessageBox.Show("Connection_ConnectionInterruptedListener");
        }

        private void reconnect()
        {
            Disconnect();
            Connect();
        }
        private IConnection createConnection()
        {
            try
            {
                string url = string.Format("tcp://{0}:{1}", Properties.Settings.Default.ServerIp, Properties.Settings.Default.ActiveMqPort);
                IConnectionFactory factory = new ConnectionFactory(url);
                IConnection connection = factory.CreateConnection(Properties.Settings.Default.ActiveMqUser,
                    Properties.Settings.Default.ActiveMqPassword);
                connection.ConnectionInterruptedListener += Connection_ConnectionInterruptedListener;
                connection.ConnectionResumedListener += Connection_ConnectionResumedListener;
                connection.ExceptionListener += Connection_ExceptionListener;
                connection.ClientId = ClientId;
                return connection;
            }
            catch (Exception e)
            {
                _logger.Error(e.Message, e.ToString());
                return null;
            }
        }
        private void connecting()
        {
            if (!_isConnecting)
            {
                string[] topics = {
                        "Airline",
                        "Information",
                        "Mission",
                        "UAV",
                        "WorkStation",
                        "Zone"
                    };

                _isConnecting = true;
                while (_connection == null && _isConnecting)
                {
                    _connection = createConnection();
                    if (_connection != null)
                    {
                        _session = _connection.CreateSession();
                        foreach (var topic in topics)
                        {
                            IMessageConsumer consumer = _session.CreateConsumer(new ActiveMQTopic(topic));
                            consumer.Listener += Consumer_Listener;
                        }
                        _connection.Start();
                        _isConnecting = false;
                    }
                    if (_isConnecting)
                    {
                        Thread.Sleep(5000);
                    }
                }
            }
        }

        public async void Connect()
        {
            if (_connection == null && _session == null)
            {
                await Task.Run(() => connecting());
            }
        }

        private void Consumer_Listener(IMessage message)
        {
            try
            {
                ITextMessage textMessage = message as ITextMessage;

                if (textMessage != null)
                {
                    if (textMessage.NMSDestination.IsTopic)
                    {
                        string topicString = textMessage.NMSDestination.ToString();
                        string topicName = topicString.Substring(topicString.LastIndexOf("/") + 1);
                        string fullname = string.Format("WRJClient.Net.{0}MessageProcessor", topicName);
                        IMessageProcessor processor = Assembly.GetExecutingAssembly().CreateInstance(fullname) as IMessageProcessor;
                        if (processor != null)
                        {
                            System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
                            {
                                JObject jobj = JObject.Parse(textMessage.Text);
                                TopicData topicData = new TopicData
                                {
                                    eventId = jobj.GetValue("eventId").ToObject<int>(),
                                    id = jobj.GetValue("id")?.ToString(),
                                    data = jobj.GetValue("data")?.ToString()
                                };
                                processor.Process(topicData);
                                //_logger.Info(string.Format("Process [{0}]：eventId[{1}], dbId:[{2}], {3} =====================", fullname, topicData.eventId, topicData.id, topicData.data));
                            });
                        }
                        else
                        {
                            _logger.Error(string.Format("Unprocessed Topic [{0}]", topicString));
                        }
                    }
                    else
                    {
                    }
                }
            }
            catch (Exception e)
            {
                _logger.Error(e.ToString());
            }
        }

        public void Disconnect()
        {
            try
            {
                _isConnecting = false;
                _session?.Dispose();
                _session = null;
                _connection?.Dispose();
                _connection = null;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

    }
}